import {createVNode, defineComponent, Fragment, PropType, VNodeTypes} from 'vue';
import {useMDXComponents} from "./context";

const TYPE_PROP_NAME = 'mdxType';

//<xxx prop1 prop2></xxx> 就会被转译为 mdx('xxx',{prop1,prop2},...)
//这里的mdx相当于就是vue中的h （react中的React.createElement）, 由 vite-mdx.ts 中 createProcessor 的 pragma 参数指定
export function mdx(type, props, children, patchFlag?, dynamicProps?, isBlockNode?) {
  let component = type;
  let newProps = props;

  const mdxType = props && props[TYPE_PROP_NAME];

  if(typeof type === 'string' || mdxType){
    component = MDXCreateElement;
    newProps = {};

    for (const key in props) {
      if (Object.hasOwnProperty.call(props,key)) {
        newProps[key] = props[key]
      }
    }

    newProps.originalType = type;
    console.log('type:', type);
    console.log('mdxType:', mdxType); //在mdx文件中指定了mdxType属性的jsx 并且是组件 这里的mdxType才有效 否则即使设置了值也会被忽略
    newProps[TYPE_PROP_NAME] = typeof type === 'string' ? type : mdxType/*也就是说自由type不为string的时候 才会用指定的mdxType. 什么情况会不为string? 自定义的组件*/;
  }

  return createVNode(component, newProps, children, patchFlag, dynamicProps, isBlockNode);
}

const MDXCreateElement = defineComponent({
  name: 'MDXCreateElement',
  props: {
    components: {
      type: Object as PropType<Record<string, VNodeTypes>>,
      default: () => ({})
    },
    originalType: String,
    [TYPE_PROP_NAME]: String,
    parentName: String /*todo 这属性貌似不是原生vue支持的 不知道干嘛的*/
  },
  setup(props, {slots}) {
    const componentsRef = useMDXComponents(() => props.components)

    return () => {
      const components = componentsRef.value;
      const {parentName, originalType, [TYPE_PROP_NAME]: type, ...etc} = props;
      console.log('type--- --- ---:',type);

      //↓ 最关键的 我们可以在Provider里定义我们会在xxx.mdx文件中会用到的组件 （或者重写我们原生html的样式，这样就可以做主题了）
      const Component =
        components[`${parentName}.${type}`] ||
        components[type] ||
        DEFAULTS[type] ||
        originalType;

      return createVNode(Component, {...etc}, slots && slots.default());
    }
  }
});

const DEFAULTS = {
  inlineCode: 'code',
  wrapper: (props, {slots}) => createVNode(Fragment, {}, slots && slots.default())
}
